//
// Created by wlk12 on 2023/4/2.
//
//
// Created by wlk12 on 2023/4/2.
//
#include <iostream>
#include <atomic>
#include <chrono>
#include <thread>

class SpinlockAtomicFlag {
public:
    void lock() {
        // test_and_set 将状态设为 true 并放回之前的状态
        // 如果状态已经为 true 则会返回ture，会一直循环
        while (flag_.test_and_set(std::memory_order_acquire)) {
        }
    }

    // 将状态设为false
    void unlock() { flag_.clear(std::memory_order_release); }

private:
    std::atomic_flag flag_ = ATOMIC_FLAG_INIT;
};

class SpinlockAtomicInt {
public:
    void lock() {
        int expected = 0;
        // compare_exchange_weak excepted 会返回原本的值
        while (!flag_.compare_exchange_weak(expected, 1, std::memory_order_acquire,
                                            std::memory_order_relaxed)) {
            expected = 0;
        }
    }

    void unlock() { flag_.store(0, std::memory_order_release); }

private:
    std::atomic<int> flag_ = 0;
};

class LockSpuriously {
public:
    void lock() {

    }

    void unlock() { }
};


int main()
{
    {
        auto t = std::chrono::system_clock::now();
        std::atomic_int32_t n= 0;
        while (n.fetch_add(1, std::memory_order_relaxed) < 100000) {}
        auto d = std::chrono::system_clock::now() - t;
        std::cout << "atomic_int add 100000 time: " << std::chrono::duration_cast<std::chrono::microseconds>(d).count() << "us" << std::endl;

        t = std::chrono::system_clock::now();
        int n2= 0;
        while (n2++ < 100000) {}
        d = std::chrono::system_clock::now() - t;
        std::cout  << "int add 100000 time: " << std::chrono::duration_cast<std::chrono::microseconds>(d).count() << "us" << std::endl;
    }

    {
        std::cout << "\n---------------Spin lock----------------------\n";
        auto st = std::chrono::system_clock::now();
//        std::atomic_int n = 0;
//        LockSpuriously lock;
//        SpinlockAtomicFlag lock;
        SpinlockAtomicInt lock;
        int n = 0;
        const int threadCount = 10;
        const int addCount = 100000;
        std::thread ts[threadCount];
        for (int i = 0; i < threadCount; ++i)
        {
            ts[i] = std::thread([&n, &lock]{
                for (int j = 0; j < addCount; ++j)
                {
                    lock.lock();
                    ++n;
                    lock.unlock();
                }
            });
        }
        for (auto& t : ts)
        {
            t.join();
        }

        auto d = std::chrono::system_clock::now() - st;
        std::cout << "++n in "  << threadCount << " threads except: " << threadCount * addCount << " , actually:" << n << " , time:"
            << std::chrono::duration_cast<std::chrono::microseconds>(d).count() << "us" << std::endl;
    }

    {
        // 需要在Release模式下测试
        std::cout << "\n---------------Reorder----------------------\n";
        int data = 0;
        std::atomic_bool ready(false);

        std::thread readThread([&data, &ready](){
            while (!ready.load(std::memory_order_relaxed)) {  }
            std::cout << "Read Thread: " + std::to_string(data) + "\n";
        });

        std::thread writeThread([&data, &ready](){
            std::this_thread::sleep_for(std::chrono::microseconds(10)); // 延迟执行
            data = 5;
            ready.store(true, std::memory_order_relaxed);
            std::cout << "Write Thread: " + std::to_string(data) + "\n";
        });

        readThread.join();
        writeThread.join();
    }
    {
         std::cout << "\n---------------Cache Coherency ----------------------\n";

        // 需要在Release模式下测试, 代码在VS2022上测试通过
        int data = 0;
        bool ready(false);

        std::thread readThread([&data, &ready]() {
            int n = 0;
            while (!ready)
            {
                //std::lock_guard g(lock);
                //std::this_thread::yield();
                //std::this_thread::sleep_for(std::chrono::microseconds(0));
                std::atomic_thread_fence(std::memory_order_seq_cst);
                ++n; /*++n 为防止空循环被过度优化*/
            }
            std::cout << n << ", Read Thread1: " + std::to_string(data) + "\n";
        });
        std::thread writeThread([&data, &ready]() {
            std::this_thread::sleep_for(std::chrono::microseconds(10)); // 延迟执行
            data = 5;
            std::atomic_thread_fence(std::memory_order_seq_cst); //防止指令重排
            ready = true;
        });

        readThread.join();
        writeThread.join();
    }


    {
        // 需要在Release模式下测试
        std::cout << "\n---------------Acquire-Release----------------------\n";
        int data = 0;
        std::atomic_bool ready{false};

        std::thread readThread([&data, &ready](){
            while (!ready.load(std::memory_order_acquire));
            std::cout << "Read Thread: " + std::to_string(data) + "\n";
        });

        std::thread writeThread([&data, &ready](){
            std::this_thread::sleep_for(std::chrono::microseconds(10)); // 延迟执行

            data = 5;
            ready.store(true, std::memory_order_release);
            
            std::cout << "Write Thread: " + std::to_string(data) + "\n";

        });

        readThread.join();
        writeThread.join();
    }


    return 0;
}